# -*- coding:UTF-8 -*-
import docker
import multiprocessing
import os

from utils.http_send import send_log, send_run_status
from utils.common import setup_log
from utils.random_port import use_open_port
from utils.get_ip import get_local_ip, get_outside_ip

logger = setup_log("docker_mgmt.log")


def process_run_docker(app_path, tag_name, use_port, umail, app_cn_name, app_desc, app_dock, app_language, app_main_code_file_path):
    client = docker.from_env()  # 创建一个docker客户端
    logger.info(f"run_docker: {umail}, {tag_name} docker from env")

    outside_ip = get_outside_ip()
    local_ip = get_local_ip()
    logs = "build Error."
    # 根据dockerfile构建images docker build -t pptdemo:latest .
    try:
        image, logs = client.images.build(
            path=app_path,  # Dockerfile 所在目录
            tag=f'{tag_name}:latest',  # 镜像标签
            rm=True  # 在构建完成后删除中间容器
        )
        send_log(f'{tag_name}:latest', outside_ip, local_ip, "",
                 image.id, "ready", "docker images build successfully")
        logger.info(
            f"run_docker: {umail}, {tag_name} docker images build successfully")
    except Exception as e:
        send_log(f'{tag_name}:latest', outside_ip, local_ip, "",
                 "", "exited", f"error: {e}, logs: {logs}")
        client.close()
        logger.error(f"run_docker: {umail}, {tag_name} images build error")
        return None

    try:
        # 启动容器
        container = client.containers.run(
            image=f'{tag_name}:latest',  # 使用的镜像
            detach=True,  # 在后台运行,参数为True时，它将启动容器，并立即返回一个对象
            # command=None,  # docker run的时候执行的命令
            # volumes:传入挂载目录，列表，可传入多个挂载目录 规则是： [“docker - path: local - path”]
            auto_remove=False,  # 当容器的进程退出时，启用在守护进程端自动删除容器
            ports={'8000/tcp': use_port}  # 将容器内部的80端口映射到主机的8080端口
        )
        # docker run -itd -p 本地端口:容器内端口 所用镜像名
        # data = {
        #     "host": outside_ip,
        #     "docker_ip": local_ip,
        #     "docker_name": f'{tag_name}:latest',
        #     "status": container.status,
        #     "container_id": container.id,
        #     "log_info": str(container.logs()),
        #     "image_id": image.id
        # }
        # 记录日志存文件
        r = send_log(f'{tag_name}:latest', outside_ip, local_ip, container.id,
                 image.id, "running", str(container.logs()))

        send_run_status(umail, tag_name, outside_ip, local_ip,
                        use_port, image.id, container.id, app_cn_name, app_desc, app_dock, app_language, app_main_code_file_path, r.get('id', -1))
        logger.info(
            f"run_docker: {umail}, {tag_name} docker containers run successfully")
    except Exception as e:
        send_log(f'{tag_name}:latest', outside_ip, local_ip, "",
                 image.id, "exited", f"error: {e}, logs: Run Error.")
        logger.error(
            f"run_docker: {umail}, {tag_name} docker containers run error")
        return None
    finally:
        client.close()

    return None


def stop_docker(host, docker_ip, docker_name, container_id, image_id):
    client = docker.from_env()

    container = None
    try:
        container = client.containers.get(container_id)
        # exit_code = container.wait()
        # print(exit_code)
    except Exception as e:
        client.close()
        logger.info("client.containers.get container_id info {}".format(e))
        return False, str(e)

    try:
        _log = str(container.logs())
        container.stop()
        # 查看返回转态码
        # exit_code = container.wait()
        # print(exit_code)

        send_log(docker_name, host, docker_ip, container_id,
                 image_id, "stop", f"logs: {_log}")
    except Exception as e:
        send_log(docker_name, host, docker_ip, container_id,
                 image_id, "stop", f"stop error: {e}")
        client.close()
        logger.error("stop container error except:{}".format(e))
        return False, str(e)

    client.close()
    return True, "ok"


def rm_docker(container_id):
    client = docker.from_env()
    container = None
    try:
        container = client.containers.get(container_id)
    except Exception as e:
        client.close()
        logger.error("docker rm failed: {}".format(e))
        return False

    try:
        # takes 1 positional argument but 4 were given
        # container.kill()
        container.remove()
    except Exception as e:
        logger.error("docker rm failed: {}".format(e))
        return False
    finally:
        client.close()

    return True


def rmi_docker(docker_id, image_name):
    # 删除 images
    client = docker.from_env()

    try:
        client.images.remove(image_name, True, False)
    except Exception as e:
        logger.error("docker rmi failed: {}".format(e))
        return False
    finally:
        client.close()
    return True


def restart_docker(host, docker_ip, docker_name, container_id, image_id):
    client = docker.from_env()
    send_log(docker_name, host, docker_ip, container_id,
             image_id, "restart", "")
    container = None
    try:
        container = client.containers.get(container_id)
    except Exception as e:
        client.close()
        return False
    try:
        container.restart()
        send_log(docker_name, host, docker_ip, container_id,
                 image_id, "running", f"{str(container.logs())}")
    except Exception as e:
        send_log(docker_name, host, docker_ip, container_id,
                 image_id, "exited", f"error: {e}")
        logger.error("exposed_restart_docker:{}".format(e))
        return False
    finally:
        client.close()

    return True


def run_docker(filename, umail, app_cn_name, app_desc, app_dock, app_language, app_main_code_file_path):
    logger.info(f"{filename}, {umail}, {app_cn_name}, {app_desc}, {app_dock}, {app_language}, {app_main_code_file_path}")

    try:
        filename = filename.split(".")[0]
    except Exception as _:
        pass

    app_path = f"{os.getcwd()}/Apps/{filename}"
    tag_name = filename.lower()
    
    local_ip = get_local_ip()
    if local_ip is None:
        return False, "获取本机IP错误"
    
    outside_ip = get_outside_ip()
    send_log(f'{tag_name}:latest', outside_ip, local_ip, "",
             "", "build", "app build")

    use_port = use_open_port()
    if use_port is None:
        return False, "端口以使用完毕, 请稍后再试"
    p = multiprocessing.Process(target=process_run_docker, args=(
        app_path, tag_name, use_port, umail, app_cn_name, app_desc, app_dock, app_language, app_main_code_file_path), daemon=True)
    p.start()

    return True, "ok"
